package game;
import java.util.LinkedList;

import exception.IllegalMoveException;


public class OthelloPosition extends AbstractOthelloPosition {

	public OthelloPosition() {
		super.initialize();
	}

	@Override
	public LinkedList<OthelloAction> getMoves() {
		char playerColor = (playerToMove) ? 'W' : 'B';
		char opponentColor = (playerToMove) ? 'B' : 'W';
		LinkedList<OthelloAction> moves = new LinkedList<OthelloAction>();
		for(int i = 1; i <= BOARD_SIZE; i++){
			for(int j = 1; j <= BOARD_SIZE; j++){
				if(canStartMove(i, j, playerColor, opponentColor)){
					getMovesInLine(i, j, playerColor, opponentColor, moves);
					getMovesInCols(i, j, playerColor, opponentColor, moves);
					getMovesInDiag(i, j, playerColor, opponentColor, moves);
				}
			}
		}
		return moves;
	}

	/**
	 * Define if a position can begins a move
	 * @param i row index of the disc
	 * @param j column index of the disc
	 * @param playerColor player's color
	 * @param opponentColor opponent's color
	 * @return
	 */
	private boolean canStartMove(int i, int j, char playerColor, char opponentColor){
		boolean ok = false;
		if(i >= 1 && j <= BOARD_SIZE){
			if(board[i][j] == playerColor && (board[i-1][j-1] == opponentColor || 
					board[i-1][j] == opponentColor ||
					board[i-1][j+1] == opponentColor ||
					board[i][j-1] == opponentColor ||
					board[i][j+1] == opponentColor ||
					board[i+1][j-1] == opponentColor || 
					board[i+1][j] == opponentColor ||
					board[i+1][j+1] == opponentColor) 
					){
				ok = true;
			}
		}
		return ok;
	}
	
	/**
	 * Get the possible moves on lines from a position
	 * @param posY row index of the disc starting the move
	 * @param posX column index of the disc starting the move
	 * @param playerColor player's color
	 * @param opponentColor opponent's color
	 * @param moves list of current possible moves
	 */
	private void getMovesInLine(int posY, int posX, char playerColor, char opponentColor, LinkedList<OthelloAction> moves){
		int j = posX - 1;
		while(j >= 1 && board[posY][j] == opponentColor){
			j--;
		}
		if(j >= 1 && j < posX - 1 && board[posY][j] == 'E'){
			moves.add(new OthelloAction(posY, j));
		}
		j = posX + 1;
		while(j <= BOARD_SIZE && board[posY][j] == opponentColor){
			j++;
		}
		if(j <= BOARD_SIZE && j > posX + 1 && board[posY][j] == 'E'){
			moves.add(new OthelloAction(posY, j));
		}
	}
	
	/**
	 * Get the possible moves on columns from a position
	 * @param posY row index of the disc starting the move
	 * @param posX column index of the disc starting the move
	 * @param playerColor player's color
	 * @param opponentColor opponent's color
	 * @param moves list of current possible moves
	 */
	private void getMovesInCols(int posY, int posX, char playerColor, char opponentColor, LinkedList<OthelloAction> moves){
		int j = posY - 1;
		while(j >= 1 && board[j][posX] == opponentColor){
			j--;
		}
		if(j >= 1 && j < posY - 1 && board[j][posX] == 'E'){
			moves.add(new OthelloAction(j, posX));
		}
		j = posY + 1;
		while(j <= BOARD_SIZE && board[j][posX] == opponentColor){
			j++;
		}
		if(j <= BOARD_SIZE && j > posY + 1 && board[j][posX] == 'E'){
			moves.add(new OthelloAction(j, posX));
		}
	}
	
	/**
	 * Get the possible moves on diagonals from a position
	 * @param posY row index of the disc starting the move
	 * @param posX column index of the disc starting the move
	 * @param playerColor player's color
	 * @param opponentColor opponent's color
	 * @param moves list of current possible moves
	 */
	private void getMovesInDiag(int posY, int posX, char playerColor, char opponentColor, LinkedList<OthelloAction> moves){
		int i = posY - 1;
		int j = posX - 1;
		while(j >= 1 && i >= 1 && board[i][j] == opponentColor){
			i--;
			j--;
		}
		if(i >= 1 && j >= 1 && i < posY - 1 && j < posX - 1 && board[i][i] == 'E'){
			moves.add(new OthelloAction(i, j));
		}
		i = posY + 1;
		j = posX + 1;
		while(j <= BOARD_SIZE && i <= BOARD_SIZE && board[i][j] == opponentColor){
			i++;
			j++;
		}
		if(i <= BOARD_SIZE && j <= BOARD_SIZE && i > posY + 1 && j > posX + 1 && board[i][j] == 'E'){
			moves.add(new OthelloAction(i, j));
		}
		i = posY - 1;
		j = posX + 1;
		while(j <= BOARD_SIZE && i >= 1 && board[i][j] == opponentColor){
			i--;
			j++;
		}
		if(i >= 1 && j <= BOARD_SIZE && i < posY - 1 && j > posX + 1 && board[i][j] == 'E'){
			moves.add(new OthelloAction(i, j));
		}
		i = posY + 1;
		j = posX - 1;
		while(j >= 1 && i <= BOARD_SIZE && board[i][j] == opponentColor){
			i++;
			j--;
		}
		if(i <= BOARD_SIZE && j >= 1 && i > posY + 1 && j < posX - 1 && board[i][j] == 'E'){
			moves.add(new OthelloAction(i, j));
		}
	}
	
	@Override
	public AbstractOthelloPosition makeMove(OthelloAction action)
			throws IllegalMoveException {
		AbstractOthelloPosition p = this;
		if(!action.isPassMove())
			p = action.apply(this); 
		playerToMove = !playerToMove;
		return p;
	}

	public void setBoard(char[][] _board) {
		board = _board;
	}
	
}
